﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.ComponentModel;

namespace InputHandler
{
    /// <summary>
    /// The EnvironmentEventHandler is a UDP Server which listens for Environment Events (sensor events from
    /// the iHome). When a sensor in the iHome wants to inform Lisa, it sends a signal to the HomeServer and the
    /// HomeServer then forwards this signal via UDP to Lisa. The EnvironmentEventHandler listens for these
    /// UDP Signals and informs Lisa about the environment events.
    /// 
    /// Thanks to: http://www.mastercsharp.com/article.aspx?ArticleID=66&&TopicID=14 for help with the UDP Code.
    /// 
    /// 
    /// </summary>
    class EnvironmentEventHandler
    {
        public event HandleInput udpEnvironmentEventReceived; //Fired when an environment event is received

        private UdpClient server;
        private IPEndPoint receivePoint;
        private int port;   //Port for the Server to use
        private int ip;     //IP Address
        private bool running;

        public EnvironmentEventHandler(int ip, int port)
        {
            this.ip = ip;
            this.port = port;
            server = new UdpClient(port);
            //Define receive point
            receivePoint = new IPEndPoint(new IPAddress(ip), port);
            running = false;
            //Start the server in a new thread
            Thread serverThread = new Thread(startServer);
            serverThread.Start();
        }

        #region UDP Server-related methods
        void startServer()
        {
            running = true;
            while (running)
            {
                //Receive DataGram
                byte[] recData = server.Receive(ref receivePoint);
                System.Text.ASCIIEncoding encode = new System.Text.ASCIIEncoding();
                //Split it up
                string recDataString = encode.GetString(recData);
                processData(recDataString);
                Thread.Sleep(20);
            }
        }

        public void stop()
        {
            running = false;
        }
        #endregion

        void processData(string data)
        {
            //TODO: Retrieve HomeServer UDP Event string.
            string[] temp = data.Split(new Char[] { '@' });
            data = temp[2];
            FireUdpEnvironmentEventReceived(new InputEventArgs(data));
        }

        #region Event-related methods

        void FireUdpEnvironmentEventReceived(InputEventArgs eventArgs)
        {
            // Get local event for thread safety purposes
            HandleInput handler = udpEnvironmentEventReceived;
            FireHandleInputEvent(handler, eventArgs);
        }

        protected void FireHandleInputEvent(HandleInput handler, InputEventArgs eventArgs)
        {
            if (handler != null)
            {
                foreach (HandleInput singleCast in handler.GetInvocationList())
                {
                    ISynchronizeInvoke syncInvoke = singleCast.Target as ISynchronizeInvoke;
                    try
                    {
                        if (syncInvoke != null && syncInvoke.InvokeRequired)
                        {
                            // Invokie the event on the main thread
                            syncInvoke.Invoke(handler, new object[] { eventArgs });
                        }
                        else
                        {
                            // Raise the event
                            singleCast(eventArgs);
                        }
                    }
                    catch
                    {
                    }
                }
            }
        }
        #endregion
    }
}
